package com.sirun.ble.manager;

import static android.content.Context.BIND_AUTO_CREATE;
import static com.sirun.ble.constants.BleConfig.BleSdkTag;
import static com.sirun.ble.constants.BleConfig.TAG_CONNECTED;
import static com.sirun.ble.constants.BleConfig.TAG_CONNECTED_AUTH;
import static com.sirun.ble.constants.BleConfig.TAG_CONNECTED_NONE;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;

import com.sirun.ble.IMyAidlInterface;
import com.sirun.ble.constants.BleConfig;
import com.sirun.ble.constants.BleUrlConfig;
import com.sirun.ble.enums.BleEnum;
import com.sirun.ble.listeners.OnBleActiveListener;
import com.sirun.ble.listeners.OnBleBindListener;
import com.sirun.ble.listeners.OnBleLoginListener;
import com.sirun.ble.listeners.OnBleRssiListener;
import com.sirun.ble.listeners.OnBleVehicleStatusListener;
import com.sirun.ble.listeners.OnBleConnectListener;
import com.sirun.ble.listeners.OnBleControlListener;
import com.sirun.ble.listeners.OnBleDebugListener;
import com.sirun.ble.listeners.OnBleDownloadListener;
import com.sirun.ble.listeners.OnBleInitListener;
import com.sirun.ble.listeners.OnBleScanListener;
import com.sirun.ble.listeners.OnBleSpareListener;
import com.sirun.ble.listeners.OnBleSystemStatusListener;
import com.sirun.ble.net.AwNetUtil;
import com.sirun.ble.receivers.BleSystemStatusReceiver;
import com.sirun.ble.services.BleService;
import com.sirun.ble.utils.AwDataUtil;
import com.sirun.ble.utils.AwLog;
import com.sirun.ble.utils.AwLogFileUtil;
import com.sirun.ble.utils.AwPermissionUtil;
import com.sirun.ble.utils.sdk.AwBleRssiUtil;
import com.sirun.ble.utils.sdk.AwBleUtil;
import com.sirun.ble.utils.sdk.AwBleSpUtil;



/**
 * @author : hzw
 */
public class BleManager {

    private static final String TAG = "MANAGER";
    private static BleManager instance;
    private Context mContext;
    private BleService mBleService;
    private OnBleInitListener mBleInitListener;
    private OnBleScanListener mBleScanListener;
    private OnBleSpareListener mBleSpareListener;
    private OnBleRssiListener mBleRssiListener;
    public OnBleConnectListener mBleConnectListener;
    public OnBleSystemStatusListener mBleSystemStatusListener;

    public OnBleControlListener mBleControlListener;
    private Handler mHandler = new Handler();
    public boolean isSecExist = false;
    private int reCheckServiceCount = 0;
    private BleSystemStatusReceiver mBleSystemStatusReceiver = new BleSystemStatusReceiver(this);
    public ServiceConnection mServiceConnection = new BleServiceConnect();
    public class BleServiceConnect implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName name, IBinder binder) {
            IMyAidlInterface proxy = IMyAidlInterface.Stub.asInterface(binder);
            try {
                mBleService = (BleService) Class.forName(proxy.getName()).newInstance();
                AwLog.d(TAG, "bleService","connect success");
            } catch (Exception e) {
                e.printStackTrace();
                AwLog.d(TAG, "bleService","connect fail");
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mBleService = null;
        }
    }

    private void bleBindDevice(final OnBleBindListener listener) {
        if(listener == null) {
            AwLog.d(TAG, "bleBindDevice", "Listener does not exist");
            return;
        }
    }

    private void resetBleScanListener() {
        if(mBleService == null) {
            AwLog.d(TAG, "resetBleScanListener", "Scan callback reset. However, the service does not exist");
            return;
        }
        mBleService.setScanListener(null);
    }

    private void resetBleConnectCallback() {
        if(mBleService == null) {
            AwLog.d(TAG, "resetBleConnectCallback", "Connect callback reset. However, the service does not exist");
            return;
        }
        mBleService.setConnectListener(null);
    }

    private void resetSpareCallback() {
        if(mBleService == null) {
            AwLog.d(TAG, "resetSpareCallback", "Other callback reset. However, the service does not exist");
            return;
        }
        mBleService.setSpareListener(null);
    }

    private void resetDownloadListener() {
        if(mBleService == null) {
            AwLog.d(TAG, "resetDownloadListener", "Download callback reset. However, the service does not exist");
            return;
        }
        mBleService.setDownloadListener(null);
    }

    private void setBleScanListener(OnBleScanListener bleScanListener) {
        if(bleScanListener == null) {
            AwLog.d(TAG, "setBleScanListener", "The parameter transfer scan callback does not exist");
            return;
        }
        if(mBleService == null) {
            AwLog.d(TAG, "setBleScanListener", "scan callback open. However, the service does not exist");
            return;
        }
        AwLog.d(TAG, "setBleScanListener", "pre check passed...");
        this.mBleScanListener = bleScanListener;
        mBleService.setScanListener(mBleScanListener);
    }

    private void setBleSpareListener(OnBleSpareListener bleSpareListener) {
        if(bleSpareListener == null) {
            AwLog.d(TAG, "setBleSpareListener","The parameter transfer other callback does not exist");
            return;
        }
        if(mBleService == null) {
            AwLog.d(TAG, "setBleSpareListener","other callback open. However, the service does not exist");
            return;
        }
        this.mBleSpareListener = bleSpareListener;
        mBleService.setSpareListener(mBleSpareListener);
    }

    public void setBleRssiListener(OnBleRssiListener bleRssiListener) {
        if(bleRssiListener == null) {
            AwLog.d(TAG, "setBleRssiListener","The parameter transfer other callback does not exist");
            return;
        }
        if(mBleService == null) {
            AwLog.d(TAG, "setBleRssiListener","other callback open. However, the service does not exist");
            return;
        }
        this.mBleRssiListener = bleRssiListener;
        mBleService.setBleRssiListener(mBleRssiListener);
    }

    public void setBleControlListener(OnBleControlListener bleControlListener) {
        if(bleControlListener == null) {
            AwLog.d(BleSdkTag, "The parameter transfer control callback does not exist");
            return;
        }
        if(mBleService == null) {
            AwLog.d(BleSdkTag, "control callback open. However, the service does not exist");
            return;
        }
        this.mBleControlListener = bleControlListener;
        mBleService.setControlListener(mBleControlListener);
    }

    private void setDownloadCallback(OnBleDownloadListener bleDownloadListener) {
        if(mBleService == null) {
            AwLog.d(TAG, "setDownloadCallback","download callback open. However, the service does not exist");
            return;
        }
        mBleService.setDownloadListener(bleDownloadListener);
    }

    private void startScan() {
        mBleService.startScanBle();
    }

    private IntentFilter makeFilter() {
        IntentFilter filter = new IntentFilter();
        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
        return filter;
    }

    private double getDistance(int rssi) {
        return AwBleRssiUtil.getDistance(rssi);
    }

    private boolean checkGPSIsOpen() {
        return AwBleUtil.checkGPSIsOpen(mContext);
    }

    private boolean checkBleIsSupport() {
        return AwBleUtil.checkBleIsSupport(mContext) && AwBleUtil.isSupportBlue(mContext);
    }

    private boolean checkBleIsClose() {
        return AwBleUtil.checkBleDevice(mContext) == BleConfig.TAG_BLE_CLOSE;
    }

    public static BleManager getInstance() {
//        TestDataUtil.testMd5();
        if (instance == null) {
            instance = new BleManager();
        }
        return instance;
    }

    public void initBleManager(final Context context, final OnBleInitListener bleInitListener) {
        AwLog.d(TAG, "initBleManager", "...");
        if(context == null) {
            AwLog.d(TAG, "initManager","context is null");
            bleInitListener.initBleFail(BleEnum.BLE_CONTEXT_NOT_EXIST.code, BleEnum.BLE_CONTEXT_NOT_EXIST.desc);
            return;
        }
        mContext = context;
        mContext.registerReceiver(mBleSystemStatusReceiver, makeFilter());
        AwLogFileUtil.getInstance()
                .setFilePrefix("_srble")
                .setMaxFileSize(3) //单位MB
                .setContext(mContext)
                .delPreDaysRecord()
                .writeDefault(true);
        setDebug(AwBleSpUtil.isDebug(mContext));
        mBleInitListener = bleInitListener;
        setBleSystemStatusListener(mBleSystemStatusListener);
        if (mServiceConnection != null) {
            AwLog.d(TAG, "initManager","serviceConnection is not null");
            Intent intent = new Intent(mContext, BleService.class);
            boolean bindResult = mContext.bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
            AwLog.d(TAG, "initManager","bindService: " + bindResult);
            mHandler.postDelayed(new InitRunnable(), 1000);
        } else {
            AwLog.d(TAG, "initManager","serviceConnection is null");
            if(bleInitListener != null) {
                bleInitListener.initBleFail(BleEnum.BLE_COMMON_SERVICE_BLE_OPEN_FAIL.code, BleEnum.BLE_COMMON_SERVICE_BLE_OPEN_FAIL.desc);
            } else {
                AwLog.d(TAG, "initManager","initListener is null");
            }
        }
    }

    public void setBleSystemStatusListener(OnBleSystemStatusListener bleSystemStatusListener) {
        this.mBleSystemStatusListener = bleSystemStatusListener;
    }

    private void closeBleService() {
        if(mBleService != null && mServiceConnection != null) {
            try {
                mContext.unbindService(mServiceConnection);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private void connectBle(BluetoothDevice dev) {
        mBleService.connectBle(dev);
    }

    public int getConnectStatus() {
        if(mBleService == null) {
            AwLog.d(TAG, "getConnectStatus", "service is null, return");
            return TAG_CONNECTED_NONE;
        }
        if(mBleService.isAuthConnected()) {
            AwLog.d(TAG, "getConnectStatus", "CONNECTED_AUTH");
            return TAG_CONNECTED_AUTH;
        }
        if(mBleService.isConnected) {
            AwLog.d(TAG, "getConnectStatus", "CONNECTED");
            return TAG_CONNECTED;
        } else {
            AwLog.d(TAG, "getConnectStatus", "CONNECTED_NONE");
            return TAG_CONNECTED_NONE;
        }
    }

    public void closeConnect() {
        if(!mBleService.isConnected && !mBleService.isAuthConnected()) {
            AwLog.d(TAG, "closeConnect", "not connect, return");
            return;
        }
        AwLog.d(TAG, "closeConnect", "pre check passed...");
        setBleConnectListener(null);
        setBleScanListener(null);
        setDownloadCallback(null);
        //        mContext.unregisterReceiver(mBleSystemStatusReceiver);
        mBleService.closeConnect(false);
    }

    public void destroyBleSdk() {
        AwLog.d(TAG, "destroyBleSdk", "...");
        closeConnect();
        closeBleService();
        reCheckServiceCount = 0;
        if(mHandler != null) {
            mHandler.removeCallbacksAndMessages(null);
            mHandler = null;
        }
    }

    public void setDebug(boolean isDebug) {
        AwLog.d(TAG, "setDebug", "isDebug: " + isDebug);
        if(mContext != null) {
            AwBleSpUtil.setDebug(mContext, isDebug);
        }
        AwLogFileUtil.getInstance().setDebug(isDebug);
        AwLog.setDebug(isDebug);
        AwLog.setLogFile(isDebug);
    }

    public void startConnect() {
        AwLog.d(TAG, "startConnect", "...");
        if(mBleConnectListener != null) {
            if(mContext == null) {
                AwLog.d(TAG, "startConnect", "context is null, return");
                mBleConnectListener.connectFail(null, BleEnum.BLE_CONTEXT_NOT_EXIST.code, BleEnum.BLE_CONTEXT_NOT_EXIST.desc);
                return;
            }
            if(!checkBleIsSupport()) {
                AwLog.d(TAG, "startConnect", "not support ble, return");
                mBleConnectListener.connectFail(null, BleEnum.BLE_COMMON_NOT_SUPPORT.code, BleEnum.BLE_COMMON_NOT_SUPPORT.desc);
                return;
            }
            if(Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
                if(!AwPermissionUtil.isHasPermissionLocation(mContext)) {
                    AwLog.d(TAG, "startConnect", "permission location is none, return");
                    mBleConnectListener.connectFail(null, BleEnum.BLE_COMMON_PERMISSION_LOCATION_NONE.code, BleEnum.BLE_COMMON_PERMISSION_LOCATION_NONE.desc);
                    return;
                }
            }
            if(!AwPermissionUtil.isHasPermissionBluetooth(mContext)) {
                AwLog.d(TAG, "startConnect", "permission bluetooth is none, return");
                mBleConnectListener.connectFail(null, BleEnum.BLE_COMMON_PERMISSION_BLUETOOTH_NONE.code, BleEnum.BLE_COMMON_PERMISSION_BLUETOOTH_NONE.desc);
                return;
            }
            if(Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
                if(!checkGPSIsOpen()) {
                    AwLog.d(TAG, "startConnect", "gps is close, return");
                    mBleConnectListener.connectFail(null, BleEnum.BLE_COMMON_GPS_CLOSED.code, BleEnum.BLE_COMMON_GPS_CLOSED.desc);
                    return;
                }
            }
            if(checkBleIsClose()) {
                AwLog.d(TAG, "startConnect", "ble is close, return");
                mBleConnectListener.connectFail(null, BleEnum.BLE_COMMON_SYSTEM_CLOSED.code, BleEnum.BLE_COMMON_SYSTEM_CLOSED.desc);
                return;
            }
        }
        AwLog.d(TAG, "startConnect", "pre check passed...");
//        setBleScanListener(mBleScanListener);
        setBleSystemStatusListener(mBleSystemStatusListener);
        setBleConnectListener(mBleConnectListener);
//        setBleSpareListener(mBleSpareListener);
        mBleService.setContext(mContext);
        mBleService.startScanBle();
    }

    public void setBleConnectListener(OnBleConnectListener bleConnectListener) {
        if(bleConnectListener == null) {
            AwLog.d(TAG, "setBleConnectListener", "The parameter transfer connect callback does not exist");
            return;
        }
        if(mBleService == null) {
            AwLog.d(TAG, "setBleConnectListener", "connect callback open. However, the service does not exist");
            return;
        }
        AwLog.d(TAG, "setBleConnectListener", "pre check passed...");
        this.mBleConnectListener = bleConnectListener;
        mBleService.setConnectListener(mBleConnectListener);
    }

    private void checkService() {
        if(mBleService == null) {
            if(reCheckServiceCount < 2) {
                reCheckServiceCount++;
                AwLog.d(TAG,"checkService", "The service does not exist after a delay of 1 second, current count: " + reCheckServiceCount);
                mHandler.postDelayed(new InitRunnable(), 1000);
            } else {
                if(mBleInitListener != null) {
                    mBleInitListener.initBleFail(BleEnum.BLE_COMMON_SERVICE_BLE_OPEN_FAIL.code, BleEnum.BLE_COMMON_SERVICE_BLE_OPEN_FAIL.desc);
                }
            }
        } else {
            reCheckServiceCount = 0;
            AwLog.d(TAG, "checkService","service execution normal");
            if(mBleInitListener != null) {
                mBleInitListener.initBleSuccess();
            } else {
                AwLog.d(TAG, "checkService","InitRunnable initListener is null");
            }
        }
    }

    public class InitRunnable implements Runnable {
        @Override
        public void run() {
            checkService();
        }
    }

    public void controlCarByBle(int type) {
        mBleService.controlCarByBle(type);
    }
}
